package com.gillion.grule.client.executor;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.gillion.grule.client.core.BusinessModel;
import com.gillion.grule.client.core.Context;
import com.gillion.grule.client.core.ContextBuilder;
import com.gillion.grule.client.exception.ExecutorException;
import com.gillion.grule.client.sync.DroolsRuleAssembly;
import com.gillion.grule.client.sync.DroolsRulePackage;
import com.gillion.grule.client.sync.RuleProvider;
import java.lang.reflect.InvocationTargetException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.kie.api.runtime.rule.ConsequenceException;
import org.kie.internal.runtime.StatefulKnowledgeSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;


/**
 * 规则执行器
 * @author wangdawei
 * @email 123027921@qq.com
 * @date 2027-06-30 19:55:59
 */
@Component
public class DroolsRuleExecutor implements RuleExecutor, InitializingBean
{
    private static final Logger logger = LoggerFactory.getLogger(DroolsRuleExecutor.class);

    @Autowired
    private RuleProvider<DroolsRulePackage> ruleProvider;

    public <T> T execute(String groupId, String artifactId, Object... args) {
        JSONArray arg = (JSONArray)JSON.toJSON(args);
        Date startTime = new Date();
        if (StringUtils.isEmpty(groupId) || StringUtils.isEmpty(artifactId) || args == null) {
            throw new ExecutorException(5000101, "规则包编码或者入参不能为空！");
        }


        Context context = ContextBuilder.newBuilder().addParams((List)arg).build();
        T rtnValue = null;
        String groupIds = groupId;
        String version = artifactId;

        try {
            DroolsRulePackage droolsRulePackage = (DroolsRulePackage)this.ruleProvider.getRule(groupId, artifactId);
            groupIds = droolsRulePackage.getGroupId();
            version = droolsRulePackage.getVersion();
            rtnValue = execute(groupId, artifactId, context, droolsRulePackage);
            Date date = new Date();
        } catch (Exception e) {
            logger.error("规则执行异常", e);
        }
        return rtnValue;
    }


    public <T> T executeThrowException(String groupId, String artifactId, Object... args) {
        JSONArray arg = (JSONArray)JSON.toJSON(args);
        Date startTime = new Date();
        if (StringUtils.isEmpty(groupId) || StringUtils.isEmpty(artifactId) || args == null) {
            throw new ExecutorException(5000101, "规则包编码或者入参不能为空！");
        }


        Context context = ContextBuilder.newBuilder().addParams((List)arg).build();
        T rtnValue = null;
        String groupIds = groupId;
        String version = artifactId;

        try {
            DroolsRulePackage droolsRulePackage = (DroolsRulePackage)this.ruleProvider.getRule(groupId, artifactId);
            groupIds = droolsRulePackage.getGroupId();
            version = droolsRulePackage.getVersion();
            rtnValue = execute(groupId, artifactId, context, droolsRulePackage);
            Date date = new Date();
        } catch (Exception e) {
            logger.error("规则执行异常", e);
            throw new RuntimeException("规则执行异常", e);
        }
        return rtnValue;
    }
    public <T> T execute(String groupId, String artifactId, Context context, DroolsRulePackage droolsRulePackage) {
        if (droolsRulePackage == null) {
            throw new ExecutorException(5000102, "获取的规则为空！");
        }
        if (droolsRulePackage.getStatus().intValue() == 1) {
            throw new ExecutorException(5000102, "该版本规则包已被停用!");
        }
        if (droolsRulePackage.getStatus().intValue() == 2) {
            throw new ExecutorException(5000102, "该版本规则包已被终止!");
        }
        context.setDubboConfig(droolsRulePackage.getDubboConfigs());
        context.setDataSources(droolsRulePackage.getDataSources());
        context.setRemoteConfig(droolsRulePackage.getRemoteConfig());
        context.setSpringCloudConfig(droolsRulePackage.getSpringCloudConfig());
        context.setValidatorConfig(droolsRulePackage.getValidatorConfig());
        context.setGroovyShellConfigs(droolsRulePackage.getGroovyShellConfigs());
        return execute(droolsRulePackage, context);
    }

    public <T> T execute(DroolsRulePackage droolsRulePackage, Context context) {
        try {
            StatefulKnowledgeSession session = droolsRulePackage.getKnowledgeBase().newStatefulKnowledgeSession();
            BusinessModel businessModel = new BusinessModel();
            context.setBusinessModel(businessModel);
            context.setPackageVariable(droolsRulePackage.getVariables());

            businessModel.init(context, droolsRulePackage);

            context.setBreakPackage(false);
            Map<String, DroolsRuleAssembly> ruleAssemblyMap = droolsRulePackage.getAssemblys();
            for (String assemblyName : ruleAssemblyMap.keySet()) {
                context.getBreakAssemblys().put(assemblyName, Boolean.valueOf(false));
            }

            droolsRulePackage.getVariables().init();
            session.insert(context);
            session.insert(droolsRulePackage);
            session.insert(businessModel);

            session.fireAllRules();
            session.dispose();
        } catch (ExecutorException e) {
            throw e;
        } catch (Exception e) {
            InvocationTargetException invocationTargetException;
            logger.error("规则执行异常", e);
            try {
                ConsequenceException exception = (ConsequenceException)e;
                invocationTargetException = (InvocationTargetException)exception.getCause().getCause().getCause().getCause().getCause();
            } catch (Exception e1) {
                throw new ExecutorException("规则执行异常！", e);
            }
            throw new ExecutorException(invocationTargetException.getTargetException().getMessage(), e);
        }

        return (T)context.getRtnValue();
    }

    public void setRuleProvider(RuleProvider<DroolsRulePackage> ruleProvider) {
        this.ruleProvider = ruleProvider;
    }

    public void afterPropertiesSet() throws Exception {
        System.setProperty("drools.dateformat", "yyyy-MM-dd HH:mm:ss");
    }

}